package com.biubiushop.aspect;

import cn.hutool.core.util.StrUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.alibaba.fastjson.JSONObject;
import com.biubiushop.constant.RedisKeyConstant;
import com.biubiushop.exception.ServiceException;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Component
@Aspect
public class WebAop {

    private static final Log logger = LogFactory.get();

    @Resource
    StringRedisTemplate stringRedisTemplate;

    @Pointcut("execution(* com.biubiushop.controller..*.*(..))")
    public void executeServiceCut() {

    }

    @Before("within(@org.springframework.web.bind.annotation.RestController *) && @annotation(com.biubiushop.annotation.Token)")
    public void doBeforeToken(JoinPoint joinPoint) throws ServiceException {
        logger.info("==============>token验证开始<==============");
        //获取RequestAttributes
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        //从获取RequestAttributes中获取HttpServletRequest的信息
        HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
        String token = request.getParameter("token");
        String userId = request.getParameter("userId");
        if (StrUtil.isAllEmpty(token, userId)) {
            throw new ServiceException("参数不能为空");
        }
        //从redis中取出该用户token
        String redisToken = stringRedisTemplate.opsForValue().get(RedisKeyConstant.getUserToken(userId));
        if (StrUtil.isEmpty(redisToken)) {
            throw new ServiceException("token为空");
        }

        if (!token.equals(redisToken)) {
            throw new ServiceException("token错误");
        }
        logger.info("==============>token验证结束<==============");
        logger.info("==============>更新token<==============");
        stringRedisTemplate.expire(RedisKeyConstant.getUserToken(userId), 15, TimeUnit.DAYS);
    }


    @Before("executeServiceCut()")
    public void doBeforeAdvice(JoinPoint joinPoint) {
        logger.info("==> 请求调用开始...");
        //获取目标方法的参数信息
        Object[] obj = joinPoint.getArgs();
        //AOP代理类的信息
        joinPoint.getThis();
        //代理的目标对象
        joinPoint.getTarget();
        //用的最多 通知的签名
        Signature signature = joinPoint.getSignature();
        //代理的是哪一个方法
        logger.info("==> 请求的方法 :" + signature.getName());
        //AOP代理类的名字
        logger.info("==> 请求的类:" + signature.getDeclaringTypeName());
        //AOP代理类的类（class）信息
        signature.getDeclaringType();
        //获取RequestAttributes
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        //从获取RequestAttributes中获取HttpServletRequest的信息
        HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
        logger.info("==> 请求者的IP：" + getIp(request));
        //如果要获取Session信息的话，可以这样写：
        //HttpSession session = (HttpSession) requestAttributes.resolveReference(RequestAttributes.REFERENCE_SESSION);
        Enumeration<String> enumeration = request.getParameterNames();
        Map<String, String> parameterMap = new HashMap<String, String>();
        while (enumeration.hasMoreElements()) {
            String parameter = enumeration.nextElement();
            parameterMap.put(parameter, request.getParameter(parameter));
        }
        String str = JSONObject.toJSONString(parameterMap);
        if (obj.length > 0) {
            logger.info("==> 请求的参数信息为：" + str);
        }
    }

    public String getIp(HttpServletRequest request) {
        String ip = request.getHeader("X-Real-IP");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Forwarded-For");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        if ("127.0.0.1".equals(ip) || "0:0:0:0:0:0:0:1".equals(ip)) {
            try {
                ip = InetAddress.getLocalHost().getHostAddress();
            } catch (UnknownHostException unknownhostexception) {
            }
        }
        return ip;
    }


    //环绕通知,更全面,但需手动调用方法
//    @Around(value = "executeServiceCut()")
//    public void doAroundAdvice(ProceedingJoinPoint proceedingJoinPoint) {
//
//        logger.info("==================1111111111111111======================");
//        doBeforeAdvice(proceedingJoinPoint);
//        logger.info("==================444444444444444444======================");
//        try {
//            proceedingJoinPoint.proceed();
//        } catch (Throwable throwable) {
//            throwable.printStackTrace();
//        }
//        logger.info("=========================8888888888==================");
//
//
//    }


}
